<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>点阵屏控制</title>
    <script src="mqtt.min.js"></script>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            min-height: 100vh;
            padding: 10px;
        }

        .container {
            /* max-width: 1200px; */
            margin: 0 auto;
        }

        header {
            text-align: center;
            margin-bottom: 15px;
            padding: 15px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
        }

        h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        }

        .subtitle {
            font-size: 1.1rem;
            opacity: 0.9;
        }

        .main-content {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
        }

        .control-panel {
            /* flex: 1; */
            max-width: 390px;
            background: rgba(0, 0, 0, 0.4);
            padding: 10px;
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
        }

        .preview-area {
            flex: 1;
            /* min-width: 300px; */
            background: rgba(0, 0, 0, 0.4);
            padding: 15px;
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
            display: flex;
            flex-direction: column;
        }

        .section-title {
            font-size: 1.4rem;
            margin-bottom: 15px;
            padding-bottom: 8px;
            border-bottom: 2px solid #4a90e2;
        }

        .form-group {
            margin-bottom: 15px;
        }

        label {
            display: block;
            margin-bottom: 6px;
            font-weight: 600;
        }

        input,
        select,
        button,
        textarea {
            width: 100%;
            padding: 10px;
            border: none;
            border-radius: 8px;
            background: rgba(255, 255, 255, 0.15);
            color: white;
            font-size: 1rem;
        }

        input:focus,
        select:focus,
        textarea:focus {
            outline: 2px solid #4a90e2;
            background: rgba(255, 255, 255, 0.25);
        }

        button {
            background: linear-gradient(to right, #4a90e2, #5e60ce);
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-top: 10px;
        }

        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
        }

        button:disabled {
            background: #666;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .status {
            margin-top: 20px;
            padding: 12px;
            border-radius: 8px;
            background: rgba(0, 0, 0, 0.3);
            font-family: monospace;
            white-space: pre-wrap;
            max-height: 270px;
            overflow-y: auto;
        }

        .color-picker {
            display: flex;
            gap: 10px;
            margin-top: 10px;
            flex-wrap: wrap;
        }

        .color-option {
            width: 35px;
            height: 35px;
            border-radius: 50%;
            cursor: pointer;
            border: 2px solid transparent;
            transition: all 0.2s;
        }

        .color-option:hover,
        .color-option.active {
            transform: scale(1.2);
            border-color: white;
        }

        .preview-grid {
            display: grid;
            gap: 2px;
            background: #000;
            padding: 10px;
            border-radius: 8px;
            margin: 10px;
            /* flex: 1; */
            /* min-height: 200px;
            max-height: 300px; */
            justify-content: center;
            align-items: center;
            overflow: auto;
        }

        .preview-cell {
            width: 20px;
            height: 20px;
            background: #222;
            border-radius: 3px;
            cursor: pointer;
        }

        .preview-cell:hover {
            transform: scale(1.1);
            box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
        }

        .command-buttons {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
            margin-top: 15px;
        }

        .command-btn {
            padding: 12px;
            font-size: 0.95rem;
        }

        .instructions {
            margin-top: 20px;
            padding: 15px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            font-size: 0.95rem;
            line-height: 1.6;
        }

        .instructions h3 {
            margin-bottom: 10px;
            color: #4a90e2;
        }

        .instructions ul {
            padding-left: 20px;
        }

        .instructions li {
            margin-bottom: 8px;
        }

        @media (max-width: 768px) {
            .main-content {
                flex-direction: column;
            }
        }

        .matrix-container {
            background: rgba(0, 0, 0, 0.6);
            /* padding: 25px; */
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
            display: flex;
            justify-content: center;
            align-items: center;
            /* min-height: 500px; */
            /* min-width: 100vw;
            min-height: 100vh; */
            flex: 1;
        }

        #mqtt-setting,
        #custom-command {
            display: none;
        }
    </style>
</head>

<body>
    <div class="container">
        <header>
            <h1>点阵屏控制</h1>
            <!-- <p class="subtitle">通过MQTT发送控制命令到显示端</p> -->
        </header>

        <div class="main-content">
            <div class="control-panel">
                <div id="mqtt-setting">

                    <h2 class="section-title">MQTT 连接设置</h2>
                    <div class="form-group">
                        <label for="broker">MQTT Broker 地址:</label>
                        <input type="text" id="broker" value="ws://192.168.50.227:8083/mqtt"
                            placeholder="例如: wss://broker.hivemq.com:8884/mqtt">
                    </div>

                    <div class="form-group">
                        <label for="clientId">客户端ID:</label>
                        <input type="text" id="clientId" value="matrix-control-123" placeholder="唯一客户端ID">
                    </div>

                    <div class="form-group">
                        <label for="commandTopic">命令主题:</label>
                        <input type="text" id="commandTopic" value="matrix/command" placeholder="发送命令的主题">
                    </div>

                    <div class="form-group">
                        <label for="dataTopic">数据主题:</label>
                        <input type="text" id="dataTopic" value="matrix/data" placeholder="发送显示数据的主题">
                    </div>

                    <button id="connectBtn">连接MQTT</button>
                    <button id="disconnectBtn" disabled>断开连接</button>
                </div>

                <h2 class="section-title" style="margin-top: 25px;">点阵配置</h2>
                <div class="form-group">
                    <label for="rows">行数:</label>
                    <input type="number" id="rows" min="1" max="100" value="32">
                </div>

                <div class="form-group">
                    <label for="cols">列数:</label>
                    <input type="number" id="cols" min="1" max="100" value="64">
                </div>

                <div class="form-group">
                    <label for="cell_size">点阵大小:</label>
                    <input type="number" id="cell_size" min="10" max="100" value="25">
                </div>

                <button id="configBtn" disabled>发送配置</button>

                <h2 class="section-title" style="margin-top: 25px;">颜色选择</h2>
                <div class="color-picker">
                    <div class="color-option active" style="background-color: #ff0000;" data-color="#ff0000"></div>
                    <div class="color-option" style="background-color: #00ff00;" data-color="#00ff00"></div>
                    <div class="color-option" style="background-color: #0000ff;" data-color="#0000ff"></div>
                    <div class="color-option" style="background-color: #ffff00;" data-color="#ffff00"></div>
                    <div class="color-option" style="background-color: #ff00ff;" data-color="#ff00ff"></div>
                    <div class="color-option" style="background-color: #00ffff;" data-color="#00ffff"></div>
                    <div class="color-option" style="background-color: #ffffff;" data-color="#ffffff"></div>
                    <div class="color-option" style="background-color: #000000;" data-color="#000000"></div>
                </div>

                <div class="form-group">
                    <label for="customColor">自定义颜色:</label>
                    <input type="color" id="customColor" value="#ff5722">
                </div>

                <h2 class="section-title" style="margin-top: 25px;">快速命令</h2>
                <div class="command-buttons">
                    <button class="command-btn" id="clearBtn" disabled>清除屏幕</button>
                    <button class="command-btn" id="testBtn" disabled>测试图案</button>
                </div>

                <div id="custom-command">
                    <h2 class="section-title" style="margin-top: 25px;">自定义命令</h2>
                    <div class="form-group">
                        <label for="customCommand">JSON命令:</label>
                        <textarea id="customCommand" rows="4"
                            placeholder='{"type": "set", "row": 0, "col": 0, "color": "#ff0000"}'></textarea>
                    </div>
                    <button id="sendCustomBtn" disabled>发送命令</button>
                </div>

                <h2 class="section-title" style="margin-top: 25px;">状态信息</h2>
                <div class="status" id="statusLog">等待连接...</div>
            </div>

            <div class="preview-area">
                <h2 class="section-title">点阵预览</h2>
                <div class="matrix-container">
                    <div class="preview-grid" id="previewGrid"></div>
                </div>

                <div class="instructions">
                    <h3>使用说明</h3>
                    <ul>
                        <li>点击发送点阵配置设置点阵行列数和大小</li>
                        <li>点击预览区域的单元格可设置颜色</li>
                        <li>使用快速命令进行常用操作</li>
                        <!-- <li>自定义命令支持完整JSON格式</li> -->
                        <li>命令类型: <code>config</code>, <code>set</code>, <code>image</code>, <code>clear</code></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 全局变量
        let client = null;
        let previewMatrix = [];
        let currentColor = '#ff0000';
        let rows = 16;
        let cols = 16;

        // DOM 元素
        const previewGrid = document.getElementById('previewGrid');
        const statusLog = document.getElementById('statusLog');
        const connectBtn = document.getElementById('connectBtn');
        const disconnectBtn = document.getElementById('disconnectBtn');
        const configBtn = document.getElementById('configBtn');
        const clearBtn = document.getElementById('clearBtn');
        const testBtn = document.getElementById('testBtn');
        const sendCustomBtn = document.getElementById('sendCustomBtn');
        const colorOptions = document.querySelectorAll('.color-option');
        const customColorInput = document.getElementById('customColor');

        // 初始化
        function init() {
            // 设置颜色选择器事件
            colorOptions.forEach(option => {
                option.addEventListener('click', () => {
                    colorOptions.forEach(opt => opt.classList.remove('active'));
                    option.classList.add('active');
                    currentColor = option.dataset.color;
                });
            });

            // 自定义颜色输入
            customColorInput.addEventListener('input', () => {
                currentColor = customColorInput.value;
                colorOptions.forEach(opt => opt.classList.remove('active'));
            });

            // MQTT连接按钮
            connectBtn.addEventListener('click', connectMQTT);
            disconnectBtn.addEventListener('click', disconnectMQTT);

            // 配置按钮
            configBtn.addEventListener('click', sendConfig);
            clearBtn.addEventListener('click', sendClear);
            testBtn.addEventListener('click', sendTestPattern);
            sendCustomBtn.addEventListener('click', sendCustomCommand);


            connectMQTT();
        }

        // 创建预览网格
        function createPreview() {
            rows = parseInt(document.getElementById('rows').value) || 16;
            cols = parseInt(document.getElementById('cols').value) || 16;

            previewMatrix = [];
            previewGrid.innerHTML = '';
            previewGrid.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;

            for (let i = 0; i < rows; i++) {
                previewMatrix[i] = [];
                for (let j = 0; j < cols; j++) {
                    const cell = document.createElement('div');
                    cell.className = 'preview-cell';
                    cell.dataset.row = i;
                    cell.dataset.col = j;

                    cell.addEventListener('click', () => {
                        previewMatrix[i][j] = currentColor;
                        cell.style.backgroundColor = currentColor;

                        // 如果已连接，发送设置命令
                        if (client && client.connected) {
                            const command = {
                                type: 'set',
                                row: i,
                                col: j,
                                color: currentColor
                            };
                            sendCommand(command);
                        }
                    });

                    previewGrid.appendChild(cell);
                    previewMatrix[i][j] = '#222222';
                }
            }
        }

        // 连接MQTT
        function connectMQTT() {
            // const broker = document.getElementById('broker').value;
            const broker = `ws://${location.hostname}:8083/mqtt`
            // const clientId = document.getElementById('clientId').value;
            const clientId = 'matrix-control-' + Math.random().toString(36).substr(2, 9)

            const commandTopic = document.getElementById('commandTopic').value;
            const dataTopic = document.getElementById('dataTopic').value;

            if (!broker || !clientId || !commandTopic || !dataTopic) {
                logStatus('请填写所有MQTT设置');
                return;
            }

            try {
                client = mqtt.connect(broker, {
                    clientId: clientId,
                    clean: true,
                    connectTimeout: 4000,
                    reconnectPeriod: 1000,
                });

                client.on('connect', () => {
                    logStatus('MQTT连接成功');
                    connectBtn.disabled = true;
                    disconnectBtn.disabled = false;
                    configBtn.disabled = false;
                    clearBtn.disabled = false;
                    testBtn.disabled = false;
                    sendCustomBtn.disabled = false;
                    // 创建初始预览
                    createPreview();
                });

                client.on('error', (error) => {
                    logStatus(`MQTT连接错误: ${error.message}`);
                });

                client.on('close', () => {
                    logStatus('MQTT连接已断开');
                    connectBtn.disabled = false;
                    disconnectBtn.disabled = true;
                    configBtn.disabled = true;
                    clearBtn.disabled = true;
                    testBtn.disabled = true;
                    sendCustomBtn.disabled = true;
                });

            } catch (error) {
                logStatus(`MQTT连接失败: ${error.message}`);
            }
        }

        // 断开MQTT连接
        function disconnectMQTT() {
            if (client) {
                client.end();
                client = null;
                logStatus('MQTT连接已断开');
                connectBtn.disabled = false;
                disconnectBtn.disabled = true;
                configBtn.disabled = true;
                clearBtn.disabled = true;
                testBtn.disabled = true;
                sendCustomBtn.disabled = true;
            }
        }

        // 发送命令
        function sendCommand(command) {
            if (!client || !client.connected) {
                logStatus('MQTT未连接');
                return;
            }

            const commandTopic = document.getElementById('commandTopic').value;
            client.publish(commandTopic, JSON.stringify(command));
            logStatus(`发送命令: ${JSON.stringify(command)}`);
        }

        // 发送配置
        function sendConfig() {
            rows = parseInt(document.getElementById('rows').value) || 16;
            cols = parseInt(document.getElementById('cols').value) || 16;
            let cell_size = parseInt(document.getElementById('cell_size').value) || 25;

            if (rows < 1 || rows > 100 || cols < 1 || cols > 100) {
                logStatus('行数和列数必须在1-50之间');
                return;
            }

            const config = {
                type: 'config',
                rows: rows,
                cols: cols,
                cell_size
            };

            sendCommand(config);
            createPreview(); // 更新预览
        }

        // 发送清除命令
        function sendClear() {
            const clearCommand = { type: 'clear' };
            sendCommand(clearCommand);

            // 清除预览
            for (let i = 0; i < rows; i++) {
                for (let j = 0; j < cols; j++) {
                    previewMatrix[i][j] = '#222222';
                    const cell = document.querySelector(`.preview-cell[data-row="${i}"][data-col="${j}"]`);
                    if (cell) cell.style.backgroundColor = '#222222';
                }
            }
        }

        // 发送测试图案
        function sendTestPattern() {
            // 创建一个简单的测试图案
            const testData = [];
            for (let i = 0; i < rows; i++) {
                testData[i] = [];
                for (let j = 0; j < cols; j++) {
                    if (i === 0 || i === rows - 1 || j === 0 || j === cols - 1) {
                        testData[i][j] = '#ff0000'; // 红色边框
                    } else if (i === Math.floor(rows / 2) && j === Math.floor(cols / 2)) {
                        testData[i][j] = '#00ff00'; // 绿色中心点
                    } else if ((i + j) % 4 === 0) {
                        testData[i][j] = '#0000ff'; // 蓝色对角线
                    } else {
                        testData[i][j] = '#222222'; // 背景
                    }
                }
            }

            const imageCommand = {
                type: 'image',
                startRow: 0,
                startCol: 0,
                data: testData
            };

            sendCommand(imageCommand);

            // 更新预览
            for (let i = 0; i < rows; i++) {
                for (let j = 0; j < cols; j++) {
                    previewMatrix[i][j] = testData[i][j];
                    const cell = document.querySelector(`.preview-cell[data-row="${i}"][data-col="${j}"]`);
                    if (cell) cell.style.backgroundColor = testData[i][j];
                }
            }
        }

        // 发送自定义命令
        function sendCustomCommand() {
            const customCommandText = document.getElementById('customCommand').value;
            try {
                const customCommand = JSON.parse(customCommandText);
                sendCommand(customCommand);
            } catch (e) {
                logStatus(`JSON格式错误: ${e.message}`);
            }
        }

        // 日志状态
        function logStatus(message) {
            const timestamp = new Date().toLocaleTimeString();
            statusLog.innerHTML = `[${timestamp}] ${message}\n` + statusLog.innerHTML;
            const lines = statusLog.innerHTML.split('\n');
            if (lines.length > 20) {
                statusLog.innerHTML = lines.slice(0, 20).join('\n');
            }
        }

        // 初始化应用
        window.addEventListener('DOMContentLoaded', init);
    </script>
</body>

</html>